#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "telescope.h"

const char * program_name;
int verbose;

void * xmalloc (size_t size) {
    void * ptr = malloc (size);
    /** Abort if the allocation failed.  */ 
    if (ptr == NULL)
        abort ();
    else
        return ptr;
}

void * xrealloc (void* ptr, size_t size) {
    ptr = realloc (ptr, size);
    /** Abort if the allocation failed.  */
    if (ptr == NULL)
        abort ();
    else
        return ptr;
}

char * xstrdup (const char* s) {
    char* copy = strdup (s);
    /** Abort if the allocation failed.  */ 
    if (copy == NULL)
        abort ();
    else
        return copy;
}

void system_error (const char* operation) {
    /** Generate an error message for errno.  */
    error (operation, strerror (errno));
}

void error( const char* cause, const char* message ) {
    /** Print an error message to stderr.  */
    fprintf (stderr, "%s: error: (%s) %s\n", program_name, cause, message);
    /** End the program.  */
    exit (1);
}

char * get_self_executable_directory () {
    int rval;
    char link_target[1024];
    char* last_slash;
    size_t result_length;
    char* result;
    /** Read the target of the symbolic link /proc/self/exe.  */
    rval = readlink ("/proc/self/exe", link_target, sizeof (link_target));
    if (rval == -1)
        /** The call to readlink failed, so bail.  */
        abort (); 
    else
        /** NUL-terminate the target.  */
        link_target[rval] = '\0';
    /** We want to trim the name of the executable file, to obtain the
        directory that contains it.  Find the rightmost slash.  */
    last_slash = strrchr (link_target, '/');
    if (last_slash == NULL ||last_slash == link_target)
        /** Something strange is going on.  */
        abort ();
    /** Allocate a buffer to hold the resulting path.  */
    result_length = last_slash - link_target;
    result = (char*) xmalloc (result_length + 1);
    /** Copy the result.  */
    strncpy (result, link_target, result_length);
    result[result_length] = '\0';
    return result;
}
